package org.sag.coverage;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

public class PolicySpreadSheetTestSuite {
	
	private static final String TEST_KEYWORD = "Test";
	
	private ArrayList<PolicySpreadSheetTestRecord> policyTestSuite ;
	private String policyUnderTest;

	public PolicySpreadSheetTestSuite(ArrayList<PolicySpreadSheetTestRecord> testRecords, String policyUnderTest){
		this.policyTestSuite = testRecords;
		this.policyUnderTest = policyUnderTest;
	}

	public PolicySpreadSheetTestSuite(String testSuiteSpreadSheetFile, String policyUnderTest) throws Exception{
		this(readTestSuite(testSuiteSpreadSheetFile), policyUnderTest);
	}
	
	public static ArrayList<PolicySpreadSheetTestRecord> readTestSuite(String testSuiteSpreadSheetFile) throws Exception{
		ArrayList<PolicySpreadSheetTestRecord> testSuite = new ArrayList<PolicySpreadSheetTestRecord>();
		FileInputStream inputStream = new FileInputStream(testSuiteSpreadSheetFile);				
		HSSFWorkbook workBook = new HSSFWorkbook (inputStream);
		Sheet sheet = workBook.getSheetAt(0);
		for (Row row: sheet){
			loadTestRow(testSuite, new File(testSuiteSpreadSheetFile).getParentFile(), row);
		}
		return testSuite;
	}
	
	private static void loadTestRow(ArrayList<PolicySpreadSheetTestRecord> testSuite, File testSuiteFolder, Row row){
		if (row.getCell(0)==null || row.getCell(1)==null)
			return;
		String keyword = row.getCell(0).toString().trim();
		if (keyword.equals("") || keyword.startsWith("//") || !keyword.substring(0,  TEST_KEYWORD.length()).equalsIgnoreCase(TEST_KEYWORD))
			return;
		String requestFileName = row.getCell(1)!=null? row.getCell(1).toString(): "";
		String oracle = row.getCell(2)!=null? row.getCell(2).toString(): "";
		if (!requestFileName.equals("") && !oracle.equals("")) {
			String requestString = PolicyRunner.readTextFile(testSuiteFolder.getAbsolutePath()+File.separator+requestFileName);
			testSuite.add(new PolicySpreadSheetTestRecord(keyword, requestFileName, requestString, oracle));
		}
	}

	public void writeToExcelFile(String fileName) {
		HSSFWorkbook workBook = new HSSFWorkbook();
		workBook.createSheet("test suite");
		Sheet sheet = workBook.getSheetAt(0);
		writeTitleRow(sheet, 0);
		int rowIndex = 1;
		for (PolicySpreadSheetTestRecord test : policyTestSuite) {
			writeTestRow(sheet, rowIndex++, test);
		}
		try {
			FileOutputStream out = new FileOutputStream(fileName);
			workBook.write(out);
			out.close();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	private static void writeTitleRow(Sheet sheet, int rowIndex) {
		Row titleRow = sheet.createRow(rowIndex);
		Cell[] titleCells = new Cell[3];
		for (int i = 0; i < titleCells.length; i++)
			titleCells[i] = titleRow.createCell(i);
		titleCells[0].setCellValue("Test Name");
		titleCells[1].setCellValue("Request file");
		titleCells[2].setCellValue("Expected response");
	}

	private static void writeTestRow(Sheet sheet, int rowIndex, PolicySpreadSheetTestRecord test) {
		Row testRow = sheet.createRow(rowIndex);
		Cell[] testCells = new Cell[3];
		for (int i = 0; i < testCells.length; i++)
			testCells[i] = testRow.createCell(i);
		testCells[0].setCellValue(test.getNumber());
		testCells[1].setCellValue(test.getRequestFile());
		testCells[2].setCellValue(test.getOracle());
	}


	public PolicySpreadSheetTestRecord findPolicyTest(String decision){
		for (PolicySpreadSheetTestRecord test: policyTestSuite){
			if (test.getOracle().equalsIgnoreCase(decision))
				return test;
		}
		return null;
	}
	

	public void runAllTests() throws Exception {
		try {
			PolicyRunner policyTester = new PolicyRunner(policyUnderTest);
			for (PolicySpreadSheetTestRecord test: policyTestSuite){
				PolicyCoverageFactory.currentTestID = test.getNumber();
				System.out.print("\n"+test.getNumber());
				if (test.getOracle().equals("")){
					System.out.print(": no test oracle");
					policyTester.runTestWithoutOracle(test.getNumber(), test.getRequest());
				}
				else  {
					if (policyTester.runTest(test.getNumber(), test.getRequest(), test.getOracle()))
						System.out.print(": pass");
					else
					System.out.print(": fail");
				}
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Vector<Vector<Object>> getTestData(){
		int index =1;
		Vector<Vector<Object>> data = new Vector<Vector<Object>>();
		for (PolicySpreadSheetTestRecord test: policyTestSuite){
			Vector<Object> vector = test.getTestVector();
			vector.set(0, index+"");
			data.add(vector);
			index++;
		}
		return data;
	}
	
	public void generateJUnitFile(String projectPath, String packageName, String junitFileName) throws Exception {
		StringBuilder stringBuilder = new StringBuilder("package "+packageName+";" +
				"\nimport static org.junit.Assert.*;" +
				"\nimport org.sag.coverage.PolicyRunner;"+
				"\nimport org.junit.Test;\n");
		stringBuilder.append("\npublic class "+junitFileName+" {");
		stringBuilder.append("\n\tPolicyRunner policyRunner;");
		stringBuilder.append("\n");
		stringBuilder.append("\n\tpublic "+junitFileName+"(){" );
		stringBuilder.append("\n\t\ttry{");
		stringBuilder.append("\n\t\t\tpolicyRunner = new PolicyRunner(\""+policyUnderTest+"\");");
		stringBuilder.append("\n\t\t}");
		stringBuilder.append("\n\t\tcatch (Exception e){}");
		stringBuilder.append("\n\t}");
		int index = 1;
		for (PolicySpreadSheetTestRecord test: policyTestSuite){
			if (!test.getOracle().equals("")){
				stringBuilder.append("\n\n\t@Test");
				stringBuilder.append("\n\tpublic void test"+(index++)+"()  throws Exception {");
				stringBuilder.append("\n\t\tassertTrue(");
				stringBuilder.append("policyRunner.runTestFromFile(");
				stringBuilder.append("\"" + test.getNumber()+"\", ");
				stringBuilder.append("\""+test.getRequestFile()+"\", ");
				stringBuilder.append("\""+test.getOracle()+"\"));");
				stringBuilder.append("\n\t}");
			}
		}
		stringBuilder.append("\n\n}");
		System.out.println(stringBuilder.toString());
		String[] folders = packageName.split("\\.");

		String codeFolder=folders[0];
		for (int i=1; i<folders.length; i++){
			codeFolder += File.separator+folders[i];
		}
		PolicyRunner.saveStringToTextFile(stringBuilder.toString(), new File(projectPath).getCanonicalFile()+File.separator+codeFolder+File.separator+junitFileName+".java");
	}
	
}
